﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace CommandGraph.Model
{
    /// <summary>
    /// Класс, содержащий в себе утилитные методы для решения геометрических задач
    /// </summary>
    public static class GeometricUtility
    {
        #region Regions

        /// <summary>
        /// Получить прямоугольник по двум точкам
        /// </summary>
        /// <param name="first">-</param>
        /// <param name="second">-</param>
        /// <returns>-</returns>
        public static Rectangle RectangleFromTwoPoints(Point first, Point second)
        {
            return new Rectangle(Math.Min(first.X, second.X),
                Math.Min(first.Y, second.Y),
                Math.Max(first.X, second.X),
                Math.Max(first.Y, second.Y));
        }

        /// <summary>
        /// Создать область на экране в виде полосы между двумя точками 
        /// из прямоугольников указанной ширины
        /// </summary>
        public static Region GenStrip(Point first, Point second, int width)
        {
            var result = new Region(Rectangle.Empty);

            int stepcount = Math.Abs(Math.Min(second.X - first.X, second.Y - first.Y)) + 1;
            float xstep = (stepcount != 0) ? (float)(second.X - first.X + 1) / (float)stepcount :
                (second.X - first.X + 1);
            float ystep = (stepcount != 0) ? (float)(second.Y - first.Y + 1) / (float)stepcount :
                (second.Y - first.Y + 1);
            var buffer = new RectangleF(new PointF(first.X - width / 2, first.Y - width / 2),
                new SizeF(xstep + width, ystep + width));

            for (int i = 0; i < stepcount; i++)
            {
                result.Union(buffer);
                buffer.X += xstep;
                buffer.Y += ystep;
            }

            return result;
        }
        
        #endregion

        #region Distance

        /// <summary>
        /// Получить расстояние между двумя точками
        /// </summary>
        /// <param name="first">Первая точка</param>
        /// <param name="second">Вторая точка</param>
        /// <returns>Расстояние</returns>
        public static float DistanceBetweenTwoPoints(PointF first,
            PointF second)
        {
            return (float)Math.Sqrt((first.X - second.X) * (first.X - second.X)
                + (first.Y - second.Y) * (first.Y - second.Y));
        }

        /// <summary>
        /// Получить расстояние между точкой и отрезком.
        /// Отрезок задаётся своими концами.
        /// </summary>
        /// <param name="point">Точка</param>
        /// <param name="beginning">Первый конец отрезка</param>
        /// <param name="ending">Второй конец отрезка</param>
        /// <returns>Расстояние от точки до отрезка</returns>
        public static float DistanceBetweenPointAndSegment(PointF point,
            PointF beginning,
            PointF ending)
        {
            //расстояние до прямой
            var distToLine = DistanceBetweenPointAndLine(point, beginning, ending);
            //расстояние до первого конца отрезка
            var distToBegining = DistanceBetweenTwoPoints(beginning, point);
            //расстояние до второго конца отрезка
            var distToEnding = DistanceBetweenTwoPoints(ending, point);

            if (!PointBelongsToSegment(GetPointProjectionToStraightLine(point,
                    beginning,
                    ending),
                beginning,
                ending))
                return Math.Min(distToBegining, distToEnding);

            return distToLine;
        }

        /// <summary>
        /// Получить расстояние между точкой и прямой.
        /// Прямая задаётся двумя точками.
        /// </summary>
        /// <param name="point">Точка</param>
        /// <param name="lineFirst">Первая точка прямой</param>
        /// <param name="lineSecond">Вторая точка прямой</param>
        /// <returns>Расстояние от точки до прямой</returns>
        public static float DistanceBetweenPointAndLine(PointF point,
            PointF lineFirst,
            PointF lineSecond)
        {
            var projection = GetPointProjectionToStraightLine(point, lineFirst, lineSecond);

            return DistanceBetweenTwoPoints(point, projection);
        }
        
        #endregion

        #region Point and line

        /// <summary>
        /// Получить точку, лежащую на ломаной линии, наиболее близкую к указанной
        /// Ломаная линия задаётся последовательностью точек.
        /// </summary>
        /// <param name="point">
        /// Точка, которая будет проецироваться
        /// </param>
        /// <param name="linePoints">
        /// Последовательность точек, задающая ломаную
        /// </param>
        /// <param name="segment">
        /// Номер сегмента, которому принадлежит искомая точка
        /// </param>
        /// <returns>Наиболее близкая точка</returns>
        public static PointF GetNearestPointOfBrokenLine(PointF point,
            PointF[] linePoints, out int segment)
        {
            segment = -1;
            var result = PointF.Empty;
            var mindist = float.PositiveInfinity;
            //буферы для сравнения
            var dist = float.PositiveInfinity;
            var buf = PointF.Empty;

            for (int i = 1; i < linePoints.Length; i++)
            {
                dist = GetNearestPointOfSegment(point,
                    linePoints[i - 1],
                    linePoints[i],
                    out buf);
                if (dist < mindist)
                {
                    mindist = dist;
                    result = buf;
                    segment = i - 1;
                }
            }

            return result;
        }

        /// <summary>
        /// Получить точку, принадлежащюю указанному отрезку, самую близкую к данной
        /// </summary>
        /// <param name="point">Точка, относительно которой искать самую близкую</param>
        /// <param name="beginning">Первый конец отрезка</param>
        /// <param name="ending">Второй конец отрезка</param>
        /// <param name="result">Расстояние от данной точки до искомой</param>
        /// <returns>Расстояние между данной и искомой точками</returns>
        public static float GetNearestPointOfSegment(PointF point,
            PointF beginning,
            PointF ending,
            out PointF result)
        {
            //расстояние до beginning
            var mindist = DistanceBetweenTwoPoints(point, beginning);
            result = beginning;
            //расстояние до ending
            var distToEnding = DistanceBetweenTwoPoints(point, ending);
            //сравниваем
            if (distToEnding < mindist)
            {
                result = ending;
                mindist = distToEnding;
            }
            //проекция
            var projection = GetPointProjectionToStraightLine(point,
                beginning,
                ending);
            if (PointBelongsToSegment(projection,
                beginning,
                ending))
            {
                //расстояние до линии
                var distToProj = DistanceBetweenTwoPoints(point, projection);
                //сравниваем
                if (distToProj < mindist)
                {
                    result = projection;
                    mindist = distToProj;
                }
            }

            return mindist;
        }

        /// <summary>
        /// Получить проекцию точки на указанную линию.
        /// Линия задаётся двумя точками
        /// </summary>
        /// <param name="point">Точка, которая будет проецироваться</param>
        /// <param name="lineFirst">Первая точка линии</param>
        /// <param name="lineSecond">Вторая точка линии</param>
        /// <returns>Проекция</returns>
        public static PointF GetPointProjectionToStraightLine(PointF point,
            PointF lineFirst,
            PointF lineSecond)
        {
            var a1 = lineSecond.X - lineFirst.X;
            var b1 = lineSecond.Y - lineFirst.Y;
            var c1 = a1 * point.X + b1 * point.Y;
            var a2 = b1;
            var b2 = -a1;
            var c2 = a2 * lineFirst.X + b2 * lineFirst.Y;

            return new PointF((c1 * b2 - c2 * b1) / (a1 * b2 - a2 * b1),
                (c2 * a1 - c1 * a2) / (a1 * b2 - a2 * b1));
        }

        /// <summary>
        /// Определить, принадлежит ли точка указанному отрезку.
        /// Отрезок задаётся своими концами
        /// </summary>
        /// <param name="point">Точка</param>
        /// <param name="lineFirst">Первая точка прямой</param>
        /// <param name="lineSecond">Вторая точка прямой</param>
        /// <returns>true - если принадлежит</returns>
        public static bool PointBelongsToSegment(PointF point,
            PointF beginning,
            PointF ending)
        {
            if (!PointBelongsToLine(point,
                beginning,
                ending))
                return false;

            //проверка на принадлежность отрезку
            //проверяем координату X
            if (beginning.X < ending.X)
            {
                if ((point.X < beginning.X) || (point.X > ending.X))
                    return false;
            }
            else
                if ((point.X < ending.X) || (point.X > beginning.X))
                    return false;

            //проверяем координату Y
            if (beginning.Y < ending.Y)
            {
                if ((point.Y < beginning.Y) || (point.Y > ending.Y))
                    return false;
            }
            else
                if ((point.Y < ending.Y) || (point.Y > beginning.Y))
                    return false;

            return true;
        }

        /// <summary>
        /// Определить, принадлежит ли точка указанной прямой.
        /// Прямая задаётся двумя точками
        /// </summary>
        /// <param name="point">Точка</param>
        /// <param name="lineFirst">Первая точка прямой</param>
        /// <param name="lineSecond">Вторая точка прямой</param>
        /// <returns>true - если принадлежит</returns>
        public static bool PointBelongsToLine(PointF point,
            PointF lineFirst,
            PointF lineSecond)
        {
            //определяем уравнение прямой
            var a = lineFirst.Y - lineSecond.Y;
            var b = lineSecond.X - lineFirst.X;
            var c = -a * lineFirst.X - b * lineFirst.Y;

            //подставляем точку
            return (a * point.X + b * point.Y + c) < float.Epsilon;
        }

        /// <summary>
        /// Определить, лежит ли точка внутри прямоугольника
        /// </summary>
        /// <param name="point">Точка</param>
        /// <param name="rect">Прямоугольник</param>
        /// <returns></returns>
        public static bool PointInsideTheRectangle(PointF point,
            Rectangle rect)
        {
            return (point.X >= rect.Left) && (point.X <= rect.Right)
                && (point.Y >= rect.Top) && (point.Y <= rect.Bottom);
        }

        #endregion

        #region Intersection, float

        /// <summary>
        /// Получить точку пересечения отрека и прямоугольника.
        /// Отрезок задан своими концами.
        /// </summary>
        /// <param name="segmentBeginning">
        /// Первый конец отрезка
        /// </param>
        /// <param name="segmentEnding">
        /// Второй конец отрезка
        /// </param>
        /// <param name="rectangle">
        /// Прямоугольник
        /// </param>
        /// <param name="result">Точка пересечения. 
        /// Равно PointF.Empty если указанные прямая и отрезок не пересекаются</param>
        /// <returns>true - если пересекаются</returns>
        public static bool GetIntersectionPointOfSegmentAndRectangle(PointF segmentBeginning,
            PointF segmentEnding,
            RectangleF rectangle,
            out PointF result)
        {
            bool intersects = false;
            result = PointF.Empty;
            //левая сторона прямоугольника
            intersects = GetIntersectionPointOfTwoSegments(
                new PointF(rectangle.Left, rectangle.Top),
                new PointF(rectangle.Left, rectangle.Bottom),
                segmentBeginning,
                segmentEnding,
                out result);

            if (intersects)
                return true;

            //верхняя сторона прямоугольника
            intersects = GetIntersectionPointOfTwoSegments(
                new PointF(rectangle.Left, rectangle.Top),
                new PointF(rectangle.Right, rectangle.Top),
                segmentBeginning,
                segmentEnding,
                out result);

            if (intersects)
                return true;

            //правая сторона прямоугольника
            intersects = GetIntersectionPointOfTwoSegments(
                new PointF(rectangle.Right, rectangle.Top),
                new PointF(rectangle.Right, rectangle.Bottom),
                segmentBeginning,
                segmentEnding,
                out result);

            if (intersects)
                return true;

            //нижняя сторона прямоугольника
            intersects = GetIntersectionPointOfTwoSegments(
                new PointF(rectangle.Left, rectangle.Bottom),
                new PointF(rectangle.Right, rectangle.Bottom),
                segmentBeginning,
                segmentEnding,
                out result);

            if (intersects)
                return true;

            result = PointF.Empty;
            return false;
        }

        /// <summary>
        /// Получить точку пересечения двух отрезков.
        /// Каждый отрезок задан своими концами.
        /// </summary>
        /// <param name="segmentABeginning">
        /// Первый конец первого отрезка
        /// </param>
        /// <param name="segmentAEnding">
        /// Второй конец первого отрезка
        /// </param>
        /// <param name="segmentBBeginning">
        /// Первый конец второго отрезка
        /// </param>
        /// <param name="segmentBEnding">
        /// Второй конец второго отрезка
        /// </param>
        /// <param name="result">Точка пересечения. 
        /// Равно PointF.Empty если указанные отрезки не пересекаются</param>
        /// <returns>true - если пересекаются</returns>
        public static bool GetIntersectionPointOfTwoSegments(PointF segmentABeginning,
            PointF segmentAEnding,
            PointF segmentBBeginning,
            PointF segmentBEnding,
            out PointF result)
        {
            result = PointF.Empty;
            PointF result1 = PointF.Empty;
            bool intersects1 = GetIntersectionPointOfLineAndSegment(
                segmentABeginning,
                segmentAEnding,
                segmentBBeginning,
                segmentBEnding,
                out result1);

            PointF result2 = PointF.Empty;
            bool intersects2 = GetIntersectionPointOfLineAndSegment(
                segmentBBeginning,
                segmentBEnding,
                segmentABeginning,
                segmentAEnding,
                out result2);

            if (!(intersects1 && intersects2))
            {
                result = PointF.Empty;
                return false;
            }

            result = result1;
            return true;
        }

        /// <summary>
        /// Получить точку пересечения отрека и прямой.
        /// Отрезок задан своими концами.
        /// Прямая задана двумя точками.
        /// </summary>
        /// <param name="segmentBeginning">
        /// Первый конец отрезка
        /// </param>
        /// <param name="segmentEnding">
        /// Второй конец отрезка
        /// </param>
        /// <param name="lineFirst">
        /// Одна из точек, принадлежащих прямой
        /// </param>
        /// <param name="lineSecond">
        /// Вторая точка прямой
        /// </param>
        /// <param name="result">Точка пересечения. 
        /// Равно PointF.Empty если указанные прямая и отрезок не пересекаются</param>
        /// <returns>true - если пересекаются</returns>
        public static bool GetIntersectionPointOfLineAndSegment(PointF segmentBeginning,
            PointF segmentEnding,
            PointF lineFirst,
            PointF lineSecond,
            out PointF result)
        {
            result = PointF.Empty;

            //получаем пересечение прямых
            bool intersects = GetIntersectionPointOfTwoLines(
                segmentBeginning,
                segmentEnding,
                lineFirst,
                lineSecond,
                out result);

            if (!intersects)
            {
                result = PointF.Empty;
                return false;
            }

            //проверка на принадлежность отрезку
            //проверяем координату X
            if (segmentBeginning.X < segmentEnding.X)
            {
                if ((result.X < segmentBeginning.X) || (result.X > segmentEnding.X))
                {
                    result = PointF.Empty;
                    return false;
                }
            }
            else
                if ((result.X < segmentEnding.X) || (result.X > segmentBeginning.X))
                {
                    result = PointF.Empty;
                    return false;
                }

            //проверяем координату Y
            if (segmentBeginning.Y < segmentEnding.Y)
            {
                if ((result.Y < segmentBeginning.Y) || (result.Y > segmentEnding.Y))
                {
                    result = PointF.Empty;
                    return false;
                }
            }
            else
                if ((result.Y < segmentEnding.Y) || (result.Y > segmentBeginning.Y))
                {
                    result = PointF.Empty;
                    return false;
                }

            return true;
        }

        /// <summary>
        /// Получить точку пересечения двух прямых.
        /// Каждая прямая задана двумя точками.
        /// </summary>
        /// <param name="lineAFirst">
        /// Одна из точек, принадлежащих первой прямой
        /// </param>
        /// <param name="lineAFirst">
        /// Вторая точка первой прямой
        /// </param>
        /// <param name="lineAFirst">
        /// Одна из точек, принадлежащих второй прямой
        /// </param>
        /// <param name="lineAFirst">
        /// Вторая точка второй прямой
        /// </param>
        /// <param name="result">Точка пересечения. 
        /// Равно PointF.Empty если указанные прямая и отрезок не пересекаются</param>
        /// <returns>true - если пересекаются</returns>
        public static bool GetIntersectionPointOfTwoLines(PointF lineAFirst,
            PointF lineASecond,
            PointF lineBFirst,
            PointF lineBSecond,
            out PointF result)
        {
            result = PointF.Empty;

            //коэффициенты уравенения первой прямой
            float a1 = lineASecond.Y - lineAFirst.Y,
                b1 = -lineASecond.X + lineAFirst.X,
                c1 = -a1 * lineAFirst.X - b1 * lineAFirst.Y;

            //коэффициенты уравенения второй прямой
            float a2 = lineBSecond.Y - lineBFirst.Y,
                b2 = -lineBSecond.X + lineBFirst.X,
                c2 = -a2 * lineBFirst.X - b2 * lineBFirst.Y;

            //рассматриваем вырожденные случаи
            if (lineAFirst == lineASecond)
            {
                result = lineBFirst;
                return true;
            }
            if (lineBFirst == lineBSecond)
            {
                result = lineAFirst;
                return true;
            }

            //если прямые параллельны
            //на самом деле, данное условие выполняется и когда прямые перпендикулярны
            if (Math.Abs(a1 * b2 - a2 * b1) < float.Epsilon)
            {
                //если прямые совпадают, то вовращаем любую точку
                if (Math.Abs(c1 - c2) < float.Epsilon)
                {
                    result = lineAFirst;
                    return true;
                }
                else
                {
                    result = PointF.Empty;
                    return false;
                }
            }

            //общий случай
            result.X = -(c1 * b2 - c2 * b1) / (a1 * b2 - a2 * b1);
            result.Y = (c1 * a2 - c2 * a1) / (a1 * b2 - a2 * b1);
            return true;
        }
        
        #endregion

        #region Intersection, integer

        /// <summary>
        /// Получить точку пересечения отрека и прямоугольника.
        /// Отрезок задан своими концами.
        /// </summary>
        /// <param name="segmentBeginning">
        /// Первый конец отрезка
        /// </param>
        /// <param name="segmentEnding">
        /// Второй конец отрезка
        /// </param>
        /// <param name="rectangle">
        /// Прямоугольник
        /// </param>
        /// <param name="result">Точка пересечения. 
        /// Равно PointF.Empty если указанные прямая и отрезок не пересекаются</param>
        /// <returns>true - если пересекаются</returns>
        public static bool GetIntersectionPointOfSegmentAndRectangle(Point segmentBeginning,
            Point segmentEnding,
            Rectangle rectangle,
            out Point result)
        {
            bool intersects = false;
            result = Point.Empty;
            //левая сторона прямоугольника
            intersects = GetIntersectionPointOfTwoSegments(
                new Point(rectangle.Left, rectangle.Top),
                new Point(rectangle.Left, rectangle.Bottom),
                segmentBeginning,
                segmentEnding,
                out result);

            if (intersects)
                return true;

            //верхняя сторона прямоугольника
            intersects = GetIntersectionPointOfTwoSegments(
                new Point(rectangle.Left, rectangle.Top),
                new Point(rectangle.Right, rectangle.Top),
                segmentBeginning,
                segmentEnding,
                out result);

            if (intersects)
                return true;

            //правая сторона прямоугольника
            intersects = GetIntersectionPointOfTwoSegments(
                new Point(rectangle.Right, rectangle.Top),
                new Point(rectangle.Right, rectangle.Bottom),
                segmentBeginning,
                segmentEnding,
                out result);

            if (intersects)
                return true;

            //нижняя сторона прямоугольника
            intersects = GetIntersectionPointOfTwoSegments(
                new Point(rectangle.Left, rectangle.Bottom),
                new Point(rectangle.Right, rectangle.Bottom),
                segmentBeginning,
                segmentEnding,
                out result);

            if (intersects)
                return true;

            result = Point.Empty;
            return false;
        }

        /// <summary>
        /// Получить точку пересечения двух отрезков.
        /// Каждый отрезок задан своими концами.
        /// </summary>
        /// <param name="segmentABeginning">
        /// Первый конец первого отрезка
        /// </param>
        /// <param name="segmentAEnding">
        /// Второй конец первого отрезка
        /// </param>
        /// <param name="segmentBBeginning">
        /// Первый конец второго отрезка
        /// </param>
        /// <param name="segmentBEnding">
        /// Второй конец второго отрезка
        /// </param>
        /// <param name="result">Точка пересечения. 
        /// Равно PointF.Empty если указанные отрезки не пересекаются</param>
        /// <returns>true - если пересекаются</returns>
        public static bool GetIntersectionPointOfTwoSegments(Point segmentABeginning,
            Point segmentAEnding,
            Point segmentBBeginning,
            Point segmentBEnding,
            out Point result)
        {
            result = Point.Empty;
            Point result1 = Point.Empty;
            bool intersects1 = GetIntersectionPointOfLineAndSegment(
                segmentABeginning,
                segmentAEnding,
                segmentBBeginning,
                segmentBEnding,
                out result1);

            Point result2 = Point.Empty;
            bool intersects2 = GetIntersectionPointOfLineAndSegment(
                segmentBBeginning,
                segmentBEnding,
                segmentABeginning,
                segmentAEnding,
                out result2);

            if (!(intersects1 && intersects2))
            {
                result = Point.Empty;
                return false;
            }

            result = result1;
            return true;
        }

        /// <summary>
        /// Получить точку пересечения отрека и прямой.
        /// Отрезок задан своими концами.
        /// Прямая задана двумя точками.
        /// </summary>
        /// <param name="segmentBeginning">
        /// Первый конец отрезка
        /// </param>
        /// <param name="segmentEnding">
        /// Второй конец отрезка
        /// </param>
        /// <param name="lineFirst">
        /// Одна из точек, принадлежащих прямой
        /// </param>
        /// <param name="lineSecond">
        /// Вторая точка прямой
        /// </param>
        /// <param name="result">Точка пересечения. 
        /// Равно PointF.Empty если указанные прямая и отрезок не пересекаются</param>
        /// <returns>true - если пересекаются</returns>
        public static bool GetIntersectionPointOfLineAndSegment(Point segmentBeginning,
            Point segmentEnding,
            Point lineFirst,
            Point lineSecond,
            out Point result)
        {
            result = Point.Empty;

            //получаем пересечение прямых
            bool intersects = GetIntersectionPointOfTwoLines(
                segmentBeginning,
                segmentEnding,
                lineFirst,
                lineSecond,
                out result);

            if (!intersects)
            {
                result = Point.Empty;
                return false;
            }

            //проверка на принадлежность отрезку
            //проверяем координату X
            if (segmentBeginning.X < segmentEnding.X)
            {
                if ((result.X < segmentBeginning.X) || (result.X > segmentEnding.X))
                {
                    result = Point.Empty;
                    return false;
                }
            }
            else
                if ((result.X < segmentEnding.X) || (result.X > segmentBeginning.X))
                {
                    result = Point.Empty;
                    return false;
                }

            //проверяем координату Y
            if (segmentBeginning.Y < segmentEnding.Y)
            {
                if ((result.Y < segmentBeginning.Y) || (result.Y > segmentEnding.Y))
                {
                    result = Point.Empty;
                    return false;
                }
            }
            else
                if ((result.Y < segmentEnding.Y) || (result.Y > segmentBeginning.Y))
                {
                    result = Point.Empty;
                    return false;
                }

            return true;
        }

        /// <summary>
        /// Получить точку пересечения двух прямых.
        /// Каждая прямая задана двумя точками.
        /// </summary>
        /// <param name="lineAFirst">
        /// Одна из точек, принадлежащих первой прямой
        /// </param>
        /// <param name="lineAFirst">
        /// Вторая точка первой прямой
        /// </param>
        /// <param name="lineAFirst">
        /// Одна из точек, принадлежащих второй прямой
        /// </param>
        /// <param name="lineAFirst">
        /// Вторая точка второй прямой
        /// </param>
        /// <param name="result">Точка пересечения. 
        /// Равно PointF.Empty если указанные прямая и отрезок не пересекаются</param>
        /// <returns>true - если пересекаются</returns>
        public static bool GetIntersectionPointOfTwoLines(Point lineAFirst,
            Point lineASecond,
            Point lineBFirst,
            Point lineBSecond,
            out Point result)
        {
            result = Point.Empty;

            //коэффициенты уравенения первой прямой
            float a1 = lineASecond.Y - lineAFirst.Y,
                b1 = -lineASecond.X + lineAFirst.X,
                c1 = -a1 * lineAFirst.X - b1 * lineAFirst.Y;

            //коэффициенты уравенения второй прямой
            float a2 = lineBSecond.Y - lineBFirst.Y,
                b2 = -lineBSecond.X + lineBFirst.X,
                c2 = -a2 * lineBFirst.X - b2 * lineBFirst.Y;

            //рассматриваем вырожденные случаи
            if (lineAFirst == lineASecond)
            {
                result = lineBFirst;
                return true;
            }
            if (lineBFirst == lineBSecond)
            {
                result = lineAFirst;
                return true;
            }

            //если прямые параллельны
            //на самом деле, данное условие выполняется и когда прямые перпендикулярны
            if (Math.Abs(a1 * b2 - a2 * b1) < float.Epsilon)
            {
                //если прямые совпадают, то вовращаем любую точку
                if (Math.Abs(c1 - c2) < float.Epsilon)
                {
                    result = lineAFirst;
                    return true;
                }
                else
                {
                    result = Point.Empty;
                    return false;
                }
            }

            //общий случай
            result.X = (int)Math.Round(-(c1 * b2 - c2 * b1) / (a1 * b2 - a2 * b1));
            result.Y = (int)Math.Round((c1 * a2 - c2 * a1) / (a1 * b2 - a2 * b1));
            return true;
        }
        
        #endregion
    }
}
